package com.getpebble.android.framework.notification.gmail;

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import com.getpebble.android.common.core.trace.Trace;
import com.getpebble.android.common.core.util.PblPreferences;
import com.getpebble.android.common.core.util.PblPreferences.PrefKey;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.GooglePlayServicesAvailabilityException;
import com.google.android.gms.auth.UserRecoverableAuthException;
import com.sun.mail.imap.IMAPFolder;
import java.io.IOException;
import javax.mail.MessagingException;
import javax.mail.Store;

public class Gmail {
    private static final String GMAIL_HOST = "imap.gmail.com";
    private static final int GMAIL_PORT = 993;
    private static final String GMAIL_SCOPE = "oauth2:https://mail.google.com/";
    public static int REQUEST_CODE_AUTH = 1001;
    private static final String TAG = Gmail.class.getSimpleName();

    public enum LoginStatus {
        SUCCESS,
        CREDENTIALS_FAILED,
        PERMISSION_REQUIRED,
        PLAY_AVAILABILITY_ERROR,
        UNKNOWN_ERROR
    }

    public static boolean validateNewAccount(Fragment fragment, Handler completionHandler, String address) {
        String oauthToken = null;
        Message msg = null;
        boolean loggedIn = false;
        Activity activity = fragment.getActivity();
        if (activity == null) {
            Trace.error(TAG, "validateNewAccount: activity was null");
            return false;
        }
        PblPreferences prefs = new PblPreferences(activity);
        if (completionHandler == null) {
            Trace.warning(TAG, "completionHandler is null");
            return false;
        }
        try {
            Trace.verbose(TAG, "Getting auth token");
            oauthToken = GoogleAuthUtil.getToken(fragment.getActivity(), address, GMAIL_SCOPE);
            Trace.verbose(TAG, "Got token");
        } catch (GooglePlayServicesAvailabilityException playEx) {
            Trace.verbose(TAG, "PLAY_AVAILABILITY_ERROR");
            msg = completionHandler.obtainMessage(LoginStatus.PLAY_AVAILABILITY_ERROR.ordinal());
            msg.arg1 = playEx.getConnectionStatusCode();
        } catch (UserRecoverableAuthException recoverableException) {
            Trace.verbose(TAG, "UserRecoverableAuthException");
            fragment.startActivityForResult(recoverableException.getIntent(), REQUEST_CODE_AUTH);
            msg = completionHandler.obtainMessage(LoginStatus.PERMISSION_REQUIRED.ordinal());
        } catch (GoogleAuthException authEx) {
            Trace.warning(TAG, "Unrecoverable authentication exception: " + authEx.getMessage(), authEx);
            msg = completionHandler.obtainMessage(LoginStatus.CREDENTIALS_FAILED.ordinal());
        } catch (IOException ioEx) {
            Trace.info(TAG, "transient error encountered: " + ioEx.getMessage());
            msg = completionHandler.obtainMessage(LoginStatus.UNKNOWN_ERROR.ordinal());
        }
        if (oauthToken != null) {
            try {
                attemptLoginOnTokenReceived(prefs, address, oauthToken);
                msg = completionHandler.obtainMessage(LoginStatus.SUCCESS.ordinal());
                loggedIn = true;
            } catch (MessagingException mex) {
                Trace.warning(TAG, "progThread: run(): MessagingException ", mex);
                msg = completionHandler.obtainMessage(LoginStatus.CREDENTIALS_FAILED.ordinal());
            } catch (Exception e) {
                Trace.warning(TAG, "gmailScreen: progThread: run(): Unknown exception", e);
                msg = completionHandler.obtainMessage(LoginStatus.UNKNOWN_ERROR.ordinal());
            }
        }
        if (msg == null) {
            msg = completionHandler.obtainMessage(LoginStatus.UNKNOWN_ERROR.ordinal());
        }
        msg.obj = address;
        msg.sendToTarget();
        return loggedIn;
    }

    public static String getGmailTokenFromBackground(Context context, String address, Intent onFinish) {
        String oauthToken = null;
        try {
            oauthToken = GoogleAuthUtil.getTokenWithNotification(context, address, GMAIL_SCOPE, null, onFinish);
        } catch (UserRecoverableAuthException recoverableException) {
            Trace.debug(TAG, "UserRecoverableAuthException", recoverableException);
        } catch (GoogleAuthException authEx) {
            Trace.info(TAG, "Unrecoverable authentication exception", authEx);
        } catch (IOException ioEx) {
            Trace.info(TAG, "transient error encountered", ioEx);
        }
        return oauthToken;
    }

    public static String getGmailTokenFromBackground(Context context, String address) {
        String oauthToken = null;
        try {
            oauthToken = GoogleAuthUtil.getToken(context, address, GMAIL_SCOPE, null);
        } catch (UserRecoverableAuthException recoverableException) {
            Trace.debug(TAG, "UserRecoverableAuthException", recoverableException);
        } catch (GoogleAuthException authEx) {
            Trace.info(TAG, "Unrecoverable authentication exception", authEx);
        } catch (IOException ioEx) {
            Trace.info(TAG, "transient error encountered", ioEx);
        }
        return oauthToken;
    }

    private static void attemptLoginOnTokenReceived(PblPreferences prefs, String address, String oauthToken) throws MessagingException, Exception {
        Trace.verbose(TAG, "Getting store...");
        Store store = getStoreForAccount(address, oauthToken);
        Trace.verbose(TAG, "Got store");
        IMAPFolder fldr = (IMAPFolder) store.getFolder("INBOX");
        fldr.open(1);
        int inboxSize = fldr.getMessageCount();
        prefs.getSharedPreferences().edit().putLong(prefs.prefKeyToString(PrefKey.GMAIL_ACCOUNT_UID_PREFIX) + address, Math.max(0, fldr.getUIDNext() - 1)).apply();
        store.close();
    }

    public static Store getStoreForAccount(String address, String token) throws Exception {
        OAuth2Authenticator.initialize();
        return OAuth2Authenticator.connectToImap(GMAIL_HOST, GMAIL_PORT, address, token, false);
    }
}
